﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Siser.Web.Models;
using Siser.Web.Authorization;
using Siser.Web.Security;
using Siser.Web.Shared;
using System.Data;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.IO;
using System.Collections;

namespace Siser.Web.Controllers
{
    public class CuentaController : Controller
    {

        private SiserEntities db = new SiserEntities();

        public ActionResult ReenvioContrasenia()
        {
            Login login = new Login();
            List<Coordenada> coordenadas = GenerarCoordenadasAleatoreas();

            login.PrimeraCoordenada = coordenadas[0];
            login.SegundaCoordenada = coordenadas[1];
            login.TerceraCoordenada = coordenadas[2];

            AgregarCoordenadasAVista(login);
            return View(login);
        }

        /// <summary>
        /// Envío de correo electronico a usuario. El envío se realiza siempre y cuando se ingrese a un usuario
        /// correcto y las coordenadas solicitadas
        /// </summary>
        /// <param name="login"></param>
        /// <returns></returns>
        [HttpPost]  
        public ActionResult ReenvioContrasenia(Login login)
        {
 
                if (Authorization.Membership.validateCoordenadas(login))
                {
                    var usuario = Authorization.Membership.getUsuarioByUsuarioNameAndCoordenadas(login);
                    var password = this.CreateRandomPassword(8);
                    //Verificación de existencia de registro activo (casos que el usuario sobrepasa el tiempo max
                    //para el nuevo ingreso y su contraseña transitoria expira
                    ingresos_transitorios ingresoTransitorio = null;
                    try
                    {
                        ingresoTransitorio = (
                                      from ingTransitorio in db.ingresos_transitorios
                                      where ingTransitorio.usuario_id == usuario.Id && ingTransitorio.vigencia == true
                                      select ingTransitorio
                                 ).First();
                    }
                    catch (Exception e)
                    {
                    }

                    if (ingresoTransitorio != null && ingresoTransitorio.vigencia == true)
                    {
                        ingresoTransitorio.contrasena_transitoria = Encryption.encryptSha1(password);
                        ingresoTransitorio.fecha_creacion = DateTime.Now;

                        //Se deja en blanco porque el campo correspondiente es 
                        //contrasena_transitoria. Ademas, para saltarnos la validacion del modelo
                        //se ingresan valores dummies los cuales no seran guardados en la bd
                        ingresoTransitorio.ContraseniaTransitoria = "aaa";
                        ingresoTransitorio.Contrasena = "aaa";
                        ingresoTransitorio.ContrasenaComparada = "aaa";
                        db.Entry(ingresoTransitorio).State = EntityState.Modified;
                        db.SaveChanges();
                    }
                    else
                    {
                        ingresos_transitorios it = new ingresos_transitorios();
                        //Valores dummies
                        it.Contrasena = "a";
                        it.contrasena_transitoria = "a";
                        it.ContrasenaComparada = "a";
                        it.ContraseniaTransitoria = "a";
                        it.usuario_id = usuario.Id;
                        it.contrasena_transitoria = Encryption.encryptSha1(password);
                        it.fecha_creacion = DateTime.Now;
                        it.vigencia = true;
                        db.ingresos_transitorios.Add(it);
                        db.SaveChanges();
                    }

                    Mail.Send("siser.noreply@cchen.cl",
                    usuario.Empleado.CorreoElectronico,
                    "Reenvío de contraseña SISER - NO RESPONDER",
                    "Estimado " + usuario.Empleado.Nombre + " : <br /><br /> " +
                    "La contraseña para hacer ingreso al sistema es " + password + "</br></br> " +
                    "<b>Debe tener en cuenta que su password solo estara vigente dentro de los proximos 15 min. </b>", true);

                    ViewBag.texto1 = "V";
                    return View();
                }
                else
                {
                    TempData["alerta"] = "* Nombre de Usuario o coordenadas erroneas";
                    return RedirectToAction("ReenvioContrasenia");
                }
        }

        /// <summary>
        /// Metodo que crea un password transitorio
        /// </summary>
        /// <param name="PasswordLength">Largo de la password aleatoria creada</param>
        /// <returns></returns>
        private string CreateRandomPassword(int PasswordLength)
        {
            string _allowedChars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
            Byte[] randomBytes = new Byte[PasswordLength];
            char[] chars = new char[PasswordLength];
            int allowedCharCount = _allowedChars.Length;

            for (int i = 0; i < PasswordLength; i++)
            {
                Random randomObj = new Random();
                randomObj.NextBytes(randomBytes);
                chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
            }
            return new string(chars);
        }

        public ActionResult CambiarPassword()
        {
            ingresos_transitorios itransitorio = new ingresos_transitorios();
            itransitorio.usuario_id = Convert.ToInt32(TempData["usuarioID"]);
            return View(itransitorio);
        }

        [HttpPost]
        public ActionResult CambiarPassword(ingresos_transitorios iTransitorio)
        {
            //Validamos que efectivamente el password ingresado anterior sea correcto
            //Si es correcto guardamos el nuevo password y cambiamos la vigencia de la password transitoria
            var passTransitoriaEncriptada = Encryption.encryptSha1(iTransitorio.ContraseniaTransitoria);
           
            ingresos_transitorios ingresoTransitorio = (
                                from it in db.ingresos_transitorios
                                where it.contrasena_transitoria == passTransitoriaEncriptada && it.usuario_id == iTransitorio.usuario_id
                                && it.vigencia == true
                                select it
                            ).First();

            if (ingresoTransitorio != null)
            {
                ingresoTransitorio.vigencia = false;
                
                //Valores dummies para saltar validacion del modelo
                ingresoTransitorio.ContrasenaComparada = "123";
                ingresoTransitorio.ContraseniaTransitoria = "123";
                ingresoTransitorio.Contrasena = "123";

                db.Entry(ingresoTransitorio).State = EntityState.Modified;
                db.SaveChanges();

                
                Usuario usuario = db.Usuarios.Find(iTransitorio.usuario_id);
                usuario.Contrasena = Encryption.encryptSha1(iTransitorio.Contrasena);
                usuario.ContrasenaComparada = Encryption.encryptSha1(iTransitorio.Contrasena);
                db.Entry(usuario).State = EntityState.Modified;
                try
                {
                    db.SaveChanges();
                }
                catch (DbEntityValidationException e)
                {
                    foreach (var eve in e.EntityValidationErrors)
                    {
                        Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                            eve.Entry.Entity.GetType().Name, eve.Entry.State);
                        foreach (var ve in eve.ValidationErrors)
                        {
                            Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                                ve.PropertyName, ve.ErrorMessage);
                        }
                    }
                    throw;
                }
                FormsAuthentication.SetAuthCookie(usuario.Nombre, false);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "Contraseña transitoria invalida. Favor intente nuevamente");
                return View();
            }
           
        }

         public ActionResult InicioSesion()
         {
             Login login = new Login();
             List<Coordenada> coordenadas = GenerarCoordenadasAleatoreas();

             login.PrimeraCoordenada = coordenadas[0];
             login.SegundaCoordenada = coordenadas[1];
             login.TerceraCoordenada = coordenadas[2];

             AgregarCoordenadasAVista(login);

             return View(login);
         }

        [HttpPost]
        public ActionResult InicioSesion(Login login)
        {
            if (ModelState.IsValid)
            {

                //Validación si existe un posible cambio de password
                if(Authorization.Membership.ValidateIngresoTransitorio(login))
                {
                     var id = (
                                                from u in db.Usuarios
                                                where u.Nombre == login.UserName
                                                select u.Id
                                            ).First();
                    TempData["usuarioID"] = id;
                    return RedirectToAction("CambiarPassword");
                }
                else 
                    if (Authorization.Membership.ValidateUser(login))
                    {
                        FormsAuthentication.SetAuthCookie(login.UserName, false);
                        return RedirectToAction("Index", "Home");
                    }
                    else
                       ModelState.AddModelError("", "Nombre de usuario, contraseña o coordenadas de identificación no validas");
               }

            login.Password = String.Empty;
            login.PrimeraCoordenada.Valor = String.Empty;
            login.SegundaCoordenada.Valor = String.Empty;
            login.TerceraCoordenada.Valor = String.Empty;
            AgregarCoordenadasAVista(login);
            return View(login);
        }

        public ActionResult CargarMenu()
        {
            List<Sistema> sistemas = Authorization.Membership.Getfuncionalidades(HttpContext.User.Identity.Name);
            return View(sistemas);
        }

        public ActionResult CerrarSesion()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("InicioSesion", "Cuenta");
        }

        public void AgregarCoordenadasAVista(Login login)
        {
            ViewBag.PrimeraCoordenada = login.PrimeraCoordenada.ToString();
            ViewBag.SegundaCoordenada = login.SegundaCoordenada.ToString();
            ViewBag.TerceraCoordenada = login.TerceraCoordenada.ToString();

        }

        private List<Coordenada> GenerarCoordenadasAleatoreas()
        {
            int i = 1;
            Random random = new Random();
            List<Coordenada> coordenadas = new List<Coordenada>();

            while (i <= 3)
            {
                Coordenada coordenada = new Coordenada();

                coordenada.I = random.Next(1, 5).ToString();
                coordenada.J = Authorization.Membership.ConvertNumberToLetter(random.Next(1, 5));
                coordenada.Valor = String.Empty;

                if (coordenadas.Count == 0)
                {
                    coordenadas.Add(coordenada);
                    i++;
                }
                else
                {
                    var result = from c in coordenadas
                                 where c.I == coordenada.I
                                    && c.J == coordenada.J
                                 select c;

                    if (result.ToList().Count == 0)
                    {
                        coordenadas.Add(coordenada);
                        i++;
                    }
                }
            }
            return coordenadas;
        }

    }
}